# _*_ coding utf-8 _*_
# FILENAME：.py
# DESCRIPTION:
# AUTH:
# DATE: 2022/6/110:56 上午
import datetime
import shutil
import threading

import xlrd
import xlwt
import os
from PyQt5.QtWidgets import *
from PyQt5 import QtCore
from PyQt5.QtCore import QStringListModel

from components.MessageBoxComponent import MessageBox
from constant import Scene, UploadValidateType
from models.asyncExecLogModel import AsyncUploadLogModel
from models.baseModel import get_session
from utils import assetsUtils
from utils.cacheUtils import Cache, CacheThread
from utils.commonUtils import is_number

"""
基础上传Dialog
"""
class BaseUploadDialog(QDialog):
    def __init__(self, parent=None, type=0, id=0, save_cls=None):
        super(BaseUploadDialog, self).__init__(parent)
        self.init_ui(parent)
        self.__id = id
        self.__type = type
        self.__save_cls = save_cls
        self.link_lab.clicked.connect(self.download_click)

    def init_ui(self, parent):
        self.setWindowTitle("上传")
        self.resize(450, 120)
        self.cwd = os.getcwd()  # 文件路径
        self.dicts = {}
        # 定义元素
        self.file_lab = QLabel()
        self.file_lab.setText("文件:")
        self.file_name = QLineEdit()
        self.btn_close = QPushButton()
        self.btn_close.setText('关闭')
        self.btn_close.clicked.connect(self.btn_close_click)
        self.btn_openFile = QPushButton()
        self.btn_openFile.setText('选择')
        self.btn_openFile.clicked.connect(self.on_chooseFile)
        self.btn_start = QPushButton()
        self.btn_start.setText('确定')
        self.btn_start.clicked.connect(self.read_excel)

        self.link_lab = QCommandLinkButton()
        self.link_lab.setText('下载模板')
        self.link_lab.setStyleSheet('''
                                font-size: 12px
                                          ''')

        '''布局'''
        grid = QGridLayout()
        grid.addWidget(self.file_lab, 0, 0, 1, 1)
        grid.addWidget(self.file_name, 0, 1, 1, 8)
        grid.addWidget(self.btn_openFile, 0, 12, 1, 1)
        grid.addWidget(self.link_lab, 1, 1, 1, 1)
        grid.addWidget(self.btn_start, 2, 4, 1, 1)
        grid.addWidget(self.btn_close, 2, 6, 1, 1)
        grid.setSpacing(0)
        self.setLayout(grid)

    def btn_close_click(self, parent):
        self.close()

    def cancel_btn_click(self):
        self.close()

    #  读取excel
    def read_excel(self):
        messageBox = MessageBox()
        file_path = self.file_name.text()
        if file_path == "":
            messageBox.warrning("告警", "请选择文件")
            return
        # 异步上传
        cal_thread = UploadThread(self.__id, self.__type, file_path, self.__save_cls)
        cal_thread.start()
        messageBox.warrning("提示", "提交成功，请打开上传日志查看结果！")
        self.close()

    #  写入excel
    def write_excel(self):

        fileName, file_type = QFileDialog.getSaveFileName(self, "文件保存", "/", "文件 (*.xls,*.xlsx);")

        if fileName == "":
            return
        try:
            workbook = xlwt.Workbook()

            for key, value in self.jia_dicts.items():
                worksheet = workbook.add_sheet(key)
                i = 0
                for name, values in value.items():
                    j = 0
                    worksheet.write(i, j, name)
                    worksheet.write(i, j + 1, str(values[0]))
                    worksheet.write(i, j + 2, values[1])
                    i += 1

            workbook.save(fileName)
        except Exception as e:
            print(e)

    #  打开文件目录
    def on_chooseFile(self):
        fileName_choose, filetype = QFileDialog.getOpenFileName(self,
                                                                "选取文件",
                                                                self.cwd,  # 起始路径
                                                                "Text Files (*.xls, *.xlsx);;All Files (*)")  # 设置文件扩展名过滤,用双分号间隔

        if fileName_choose == "":
            return

        self.file_name.setText(fileName_choose)

    #  打开文件目录
    def on_choosePath(self, file_path):
        if not file_path:
            return

        file_name = os.path.basename(file_path)
        # 获得包含文件路径+文件名的元组
        filePath_choose = QFileDialog.getSaveFileName(self,
                                                      "选取目录",
                                                      self.cwd + '/' + file_name,  # 起始路径
                                                      "xlsx(*.xlsx)")  # 设置文件扩展名过滤,用双分号间隔

        if filePath_choose[0] == "":
            return

        # 复制文件
        shutil.copy(file_path, filePath_choose[0])

    # 下载模版
    def download_click(self):
        file_path = assetsUtils.get_excel_path(self.__type)
        self.on_choosePath(file_path)

    @staticmethod
    def get_dialog(parent=None, id=0):
        dialog = BaseUploadDialog(parent, 0, id, BaseUpload)
        return dialog.exec()


"""
基础上传类
"""
class BaseUpload:
    def __init__(self, id):
        super(BaseUpload, self).__init__()
        self._id = id

    """
    上传校验
    """
    def validate(self, value, types, column_name, row_number):
        if (not isinstance(types, list)) or (not types):
            return True

        for type in types:
            if isinstance(type, int):
                if type == UploadValidateType.NOT_EMPTY.value:
                    if not str(value):
                        raise Exception("【" + column_name + "】不允许为空！" + "（行号：" + str(row_number) + "）")
                elif type == UploadValidateType.IS_NUMBER.value:
                    if value and not is_number(value):
                        raise Exception("【" + column_name + "】必须为数字！" + "（行号：" + str(row_number) + "）")
                elif type == UploadValidateType.DATETIME.value:
                    try:
                        datetime.datetime.strptime(value, '%Y-%m-%d %H:%M:%S')
                    except Exception:
                        raise Exception("【" + column_name + "】时间格式错误（正确格式如下: 2000-01-01 00:00:00）！" + "（行号：" + str(row_number) + "）")
            elif isinstance(type, tuple):
                if len(type) > 1:
                    if type[0] == UploadValidateType.CONTAIN_STRING.value:
                        for i in range(len(type)):
                            if i > 0:
                                if not type[i] in value:
                                    raise Exception("【" + column_name + "】必须包含’" + type[i] + "‘！" + "（行号：" + str(row_number) + "）")


    """
    上传重试
    """
    def retry(self, type, file_path):
        # 异步上传
        cal_thread = UploadThread(self._id, type, file_path, self.__class__)
        cal_thread.start()

    """
    保存数据，需要子类重写
    """
    def save(self, sheet):
        pass

    """
    创建日志
    """
    def add_log(self, type, file_path, start_time):
        file_name = os.path.basename(file_path)

        session = get_session()

        async_upload_log = AsyncUploadLogModel()
        async_upload_log.version_id = self._id
        async_upload_log.type = type
        async_upload_log.file = file_path
        async_upload_log.file_name = file_name
        async_upload_log.start_time = start_time
        async_upload_log.status = 0

        session.add(async_upload_log)

        # 提交
        session.commit()
        # 获取ID
        log_id = async_upload_log.id
        # 关闭
        session.close()
        return log_id

    """
    更新日志
    """
    def update_log(self, log_id, end_time, status, reason=None):
        session = get_session()

        params = {
            'end_time': end_time,
            'status': status,
            'reason': reason
        }
        session.query(AsyncUploadLogModel).filter(AsyncUploadLogModel.id == log_id).update(params)

        # 提交&关闭
        session.commit()
        session.close()


"""
异步上传
"""
class UploadThread(threading.Thread):
    def __init__(self, id, type, file_path, save_cls):
        super(UploadThread, self).__init__()  # 重构run函数必须写
        self.__id = id
        self.__type = type
        self.__file_path = file_path
        self.__save_cls = save_cls

    def run(self):
        file_path = self.__file_path
        save_instance = self.__save_cls(self.__id)

        start_time = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
        log_id = save_instance.add_log(self.__type, file_path, start_time)

        try:
            if file_path == "":
                raise Exception('文件路径为空！')
            else:
                try:
                    workbook = xlrd.open_workbook(file_path)
                    # 获取所有sheet
                    # print(workbook.sheet_names())
                    sheet = workbook.sheet_by_index(0)
                except Exception as e:
                    raise Exception('文件读取失败！')
                else:
                    save_instance.save(sheet)
        except Exception as e:
            # 上传失败
            end_time = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
            save_instance.update_log(log_id, end_time, 2, e)
        else:
            # 上传成功
            end_time = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
            save_instance.update_log(log_id, end_time, 1)

            # 缓存数据
            cache_type = Cache.get_cache_type(Scene.UPLOAD.value, self.__type)
            cache_thread = CacheThread(cache_type, self.__id)
            cache_thread.start()